/**
 * @file jrtc_client.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_watch.h"

#if USE_LV_WATCH_VIDEOCALL != 0
#include <jrtc.h>
#include "../../../lv_drivers/display/scaler.h"
/*********************
*      DEFINES
*********************/
#define VIDEO_CALL_CFG_FILE         "C:/video_call_cfg"

/**********************
*      TYPEDEFS
**********************/
typedef enum jrtc_state voip_jrtc_state_t;
typedef enum jrtc_error voip_jrtc_error_t;
typedef struct jrtc_image_t  voip_jrtc_image_t;

typedef struct {
    void /*lv_task_t*/ *state_task;
    voip_jrtc_image_t txframe;
    voip_jrtc_image_t rxframe;
    void* jrtc_ptr;
    TIMER_ID closed_timer_id;
    uint8_t closing;
} voip_jrtc_t;

typedef struct {
    uint8_t valid;
    char appkey[40];
    char key[40];
    char uid[40];
    char roomid[40];
    char srvURL[40];
} voip_jrtc_cfg_t;

/**********************
*  STATIC VARIABLES
**********************/
extern voip_phone_call_params_t voipcall_params;
static voip_jrtc_t voip_jrtc;
static voip_jrtc_cfg_t voip_cfg;

/**********************
*  STATIC PROTOTYPES
**********************/
static void voip_jrtc_config(void);
static int8_t voip_jrtc_open(const char* roomid, MODEM_VIDEO_CALL_TYPE calltype);
static uint8_t voip_jrtc_get_image(void * preview_buf);
static void voip_jrtc_on_state(lv_task_t * task);
static void voip_jrtc_cleanup(void);
static void voip_jrtc_timeout_cb(void * para);

/**********************
 *   FUNCTIONS DECLARATION
 ***********************/
extern UINT32  OsaGetTicks(void *pForFutureUse);

/**********************
 *   GLOBAL FUNCTIONS
 ***********************/
void voip_call_init(void)
{
    Hal_Mem_Set(&voip_jrtc, 0, sizeof(voip_jrtc_t));

    voip_jrtc_config();
}

int8_t voip_call_dial_req(MODEM_VIDEO_CALL_TYPE calltype, char * pContactUri)
{
    printf("%s: calltype=%d, number=%s\n", __FUNCTION__, calltype, pContactUri);
    int8_t ret = -1;

#if VOIP_JUPHOON_TEST
    voip_jrtc_config();

    if (NULL == voip_jrtc.jrtc_ptr) {
        ret = voip_jrtc_open(voip_cfg.roomid, calltype);
    }

#else
    if (NULL == voip_jrtc.jrtc_ptr) {
        ret = voip_jrtc_open(pContactUri, calltype);
    }
#endif

    Hal_Mem_Free(pContactUri);
    return ret;
}

void voip_call_hangup_req(BOOL bye)
{
    printf("%s: jrtc_ptr=%p, bye=%d\n", __FUNCTION__, voip_jrtc.jrtc_ptr, bye);

    if (NULL != voip_jrtc.jrtc_ptr) {
        voip_jrtc_error_t err;
        if(TRUE == bye) {
            err = JRTC_EBYE;
        } else {
            err = JRTC_EAUDIOCALL;
        }

        jrtc_close(voip_jrtc.jrtc_ptr, err);
        voip_jrtc.closing = 1;
    } else {
        watch_voip_call_response_no_carrier(0, 0);
    }
}

int8_t voip_call_answer_req(void)
{
    printf("%s: jrtc_ptr=%p\n", __FUNCTION__, voip_jrtc.jrtc_ptr);
    int8_t ret = -1;

    if (NULL == voip_jrtc.jrtc_ptr) {
        ret = voip_jrtc_open(voipcall_params.number, voipcall_params.voip_call_type);
    }
    return ret;
}

void voip_call_reject_req(BOOL bye)
{
    printf("%s: jrtc_ptr=%p, bye=%d\n", __FUNCTION__, voip_jrtc.jrtc_ptr, bye);

    if (NULL != voip_jrtc.jrtc_ptr) {
        voip_jrtc_error_t err;
        if(TRUE == bye) {
            err = JRTC_EBYE;
        } else {
            err = JRTC_EAUDIOCALL;
        }

        jrtc_close(voip_jrtc.jrtc_ptr, err);
        voip_jrtc.closing = 1;
    } else {
        watch_voip_call_response_no_carrier(0, 0);
    }
}

/**********************
*   STATIC FUNCTIONS
**********************/
static void voip_jrtc_config(void)
{
    lv_fs_file_t file;
    uint32_t size;
    char *buf = NULL;

    printf("%s: voip_cfg.valid=%d\n", __FUNCTION__, voip_cfg.valid);

    if(1 == voip_cfg.valid) {
        return;
    }

    Hal_Mem_Set(&voip_cfg, 0, sizeof(voip_jrtc_cfg_t));

    uint8_t res = lv_fs_open(&file, VIDEO_CALL_CFG_FILE, LV_FS_MODE_RD);
    if(LV_FS_RES_OK == res) {
        lv_fs_size(&file, &size);
        buf = lv_mem_alloc(size + 1);
        memset(buf, 0, size + 1);
        lv_fs_read(&file, buf, size, NULL);
        //printf("%s: %s\n", __FUNCTION__, buf);

        sscanf(buf, "appkey=%s key=%s uid=%s roomid=%s srvURL=%s",
            voip_cfg.appkey,
            voip_cfg.key,
            voip_cfg.uid,
            voip_cfg.roomid,
            voip_cfg.srvURL);

        voip_cfg.valid = 1;

        lv_mem_free(buf);
        lv_fs_close(&file);
    } else {
        printf("%s: lv_fs_open fail, res=%d\n", __FUNCTION__, res);

        strncpy(voip_cfg.appkey, "1234567890abcd1234567890", 40);
        strncpy(voip_cfg.key, "abc123def4567890", 40);
        strncpy(voip_cfg.uid, "user1", 40);
        strncpy(voip_cfg.roomid, "user2", 40);
        strncpy(voip_cfg.srvURL, "http:example.com:1234;1.1.1.1:1234", 40);
    }

    //jrtc_config(voip_cfg.appkey, voip_cfg.uid, voip_cfg.srvURL, voip_cfg.key);
    jrtc_config(voip_cfg.appkey, voip_cfg.uid, voip_cfg.key, "");
}

static int8_t voip_jrtc_open(const char* roomid, MODEM_VIDEO_CALL_TYPE calltype)
{
    printf("%s: roomid=%s, calltype=%d\n", __FUNCTION__, roomid, calltype);
    Hal_Mem_Set(&voip_jrtc, 0, sizeof(voip_jrtc_t));

    if (MODEM_VIDEO_CALL_TYPE_VIDEO == calltype) {
        voip_jrtc.rxframe.width  = voip_jrtc.txframe.width  = 176;
        voip_jrtc.rxframe.height = voip_jrtc.txframe.height = 144;
        voip_jrtc.rxframe.fps    = voip_jrtc.txframe.fps    = 10;
        voip_jrtc.rxframe.kbps   = voip_jrtc.txframe.kbps   = 240;

        voip_jrtc.jrtc_ptr= jrtc_open(roomid, 0, &voip_jrtc.rxframe, &voip_jrtc.txframe);
    } else {
        voip_jrtc.jrtc_ptr= jrtc_open(roomid, 0, NULL, NULL);
    }

    if (!voip_jrtc.jrtc_ptr) {
        printf("%s: jrtc_open fail\n", __FUNCTION__);
        voip_jrtc_cleanup();
        return -1;
    }
    jrtc_activate(voip_jrtc.jrtc_ptr, JRTC_AUDIO|JRTC_CAMERA);

    voip_jrtc.state_task = lv_task_create(voip_jrtc_on_state, VIDEO_RENDER_PERIOD, LV_TASK_PRIO_HIGH, NULL);
    return 0;
}

static uint8_t voip_jrtc_get_image(void * preview_buf)
{
    uint8_t ret = 0;
    lv_voip_phone_obj_ext_t * ext = voip_phone_get_ext();
    LV_ASSERT_MEM(ext);

    voip_jrtc_image_t *frame = NULL;
    if(ext->local_remote_switch_flag == VOIP_REMOTE_SWITCH_REMOTE) {
        frame = &voip_jrtc.rxframe;
    } else {
        frame = &voip_jrtc.txframe;
    }

    if (frame->put != frame->get) {
#if (ENABLE_VIDEO_SCALE == 0)
        yuv420_2_rgb565(frame->width, frame->height, frame->data, preview_buf, frame->format);
#elif (defined(USE_WATCH_LITE))
        uint8 * tbuf = voip_phone_get_video_trans_buffer();
    #if SCALE_BASE_ON_HEIGHT //scale based on height
        uint16 i;
        yuv420_2_rgb565(frame->width, frame->height, frame->data, preview_buf, frame->format);

        for(i = 0; i < frame->height; i++) {
            memcpy(&tbuf[i * frame->height * sizeof(lv_color_t)], &((uint8_t *)preview_buf)[(i * frame->width + 16) * sizeof(lv_color_t)], frame->height * sizeof(lv_color_t));
        }
        rgb565_scale(frame->height, frame->height, canvas_width, canvas_heigh, tbuf, preview_buf);
//        lv_img_sw_565_scale(frame->height, frame->height, canvas_width, canvas_heigh, tbuf, preview_buf, false);
    #else //scale based on width
        yuv420_2_rgb565(frame->width, frame->height, frame->data, tbuf, frame->format);
        rgb565_scale(frame->width, frame->height, canvas_width, frame->height * canvas_width / frame->width, tbuf, preview_buf);
    #endif
#else
        Hal_Yuv420_Render(frame->width, frame->height, canvas_width, canvas_heigh, frame->data, preview_buf, frame->format);
#endif
        frame->get = frame->put;
        ret = 1;
        voip_fps_check(frame->fps);
    }

    return ret;
}

static void voip_jrtc_on_state(lv_task_t * task)
{
    voip_jrtc_error_t err;
    static int8_t oldstate = -1;
    voip_jrtc_state_t state = jrtc_state(voip_jrtc.jrtc_ptr);

    if(state != oldstate) {
        printf("%s: state=%d\n", __FUNCTION__, state);
    }

    switch(state) {
    case JRTC_CLOSED:
        if((NULL != voip_jrtc.jrtc_ptr) && (NULL == voip_jrtc.closed_timer_id)) {
        err = jrtc_error(voip_jrtc.jrtc_ptr);
        printf("%s: err=%d\n", __FUNCTION__, err);

            if(!voip_jrtc.closing) {
                jrtc_close(voip_jrtc.jrtc_ptr, JRTC_ENIL);
                voip_jrtc.closing = 1;
            }

            printf("%s: start jrtc_closed_timer\n", __FUNCTION__);
            voip_jrtc.closed_timer_id= Hal_Timer_Start(100, voip_jrtc_timeout_cb, NULL, 0);
        }

        if(MMI_VOIP_CALL_STATE_NULL != voipcall_params.state) {
            watch_voip_call_response_no_carrier(0, 1);
        }
        break;

    case JRTC_LEAVING:
        break;

    case JRTC_OPENED:
        break;

    case JRTC_JOINING:
        break;

    case JRTC_JOINED:
        break;

    case JRTC_TALKING:
        if(MMI_VOIP_CALL_STATE_ACTIVE != voipcall_params.state) {
            watch_voip_call_response_connect(0);
        }

        /* Get image */
        if (MODEM_VIDEO_CALL_TYPE_VIDEO == voipcall_params.voip_call_type) {
            void *buf = voip_phone_get_video_buffer();
            if(voip_jrtc_get_image(buf)) {
                lv_canvas_set_buffer(voip_phone_get_ext()->canvas, buf, canvas_width, canvas_heigh, LV_IMG_CF_TRUE_COLOR);
            }
        }
        break;

    default:
        break;
    }

    oldstate = state;
}

static void voip_jrtc_cleanup(void)
{
    printf("%s\n", __FUNCTION__);

    if(NULL != voip_jrtc.state_task) {
        printf("%s: delete state_task\n", __FUNCTION__);
        lv_task_del(voip_jrtc.state_task);
    }

    Hal_Mem_Set(&voip_jrtc, 0, sizeof(voip_jrtc_t));
}

static void voip_jrtc_timeout_cb(void * para)
{
    printf("%s\n", __FUNCTION__);

    voip_jrtc_cleanup();
}

#ifdef BUILD_IN_PC_SIMULATOR
struct jrtc_t* jrtc_open (const char* roomid, const char* ticket, struct jrtc_image_t* video, struct jrtc_image_t* camera)
{
    return NULL;
}

void jrtc_close (struct jrtc_t* jc, enum jrtc_error err)
{

}

void jrtc_config (const char* appkey, const char* uid, const char key[16], const char* tokens)
{

}

void jrtc_activate (struct jrtc_t* jc, int devices)

{

}


void jrtc_deactivate (struct jrtc_t* jc, int devices)
{

}


enum jrtc_state jrtc_state  (const struct jrtc_t *jc)
{
    return 0;
}


enum jrtc_error jrtc_error  (const struct jrtc_t *jc)
{
    return 0;
}


#endif

#endif // #if USE_LV_WATCH_VIDEOCALL != 0
